解析の基礎知識
ここでは解析にあたり最低限必要な情報を記しておく。問題ないとは思うがざっと目を通しておけ。
もし分からんようなら自分で調べろ、質問はするなよ?いいな。
≡用語≡
ミジンコ
まぎれもなくお前らのことだ。といっても俺もミジンコだからよろしくな('A`)
API(Application Program Interface、略してAPI)
API は Windows の様々な機能を提供するパッケージだ。これを用いることで簡単に色々な機能を持つプログラムが作れるようになる。
解析にとっては、このAPIがキモになる。また、API を用いたプログラムの形として SDK や MFC がある。
噛み砕いて説明すると、SDK は WIN32 API をそのままの形でガリガリ使いまわす方法だ。
これに対して MFS は SDK、もとい WIN32 API の細かい設定などを簡略化して WIN32 API を使えるようにしたプログラミングの型だ。
もし、プログラミングをかじろうとしてるのならまずは SDK を進める、MFC のほうが機能的に上かもしれないが
理解する、という意味では SDK のむき出しの WIN32 API を扱ったほうがいいと思うからだ。
無論、ウィンドウやメッセージの概念を理解し、ある程度プログラムを組めるのであれば MFS で全然かまわないと思うがな。
アセンブリ・アセンブラ・アセンブル・・・
色々な呼び方があるがミジンコゼミではソースコードを CPU が理解できる形にするものをアセンブラ、アセンブルと呼ぶ。
その行為自体もアセンブラ、アセンブルという言葉で表現する。
アセンブラの代表的なものだと MASM や NASM が有名だ。
また、mov や jmp、call などの命令を含め人が理解できる表示形式になっているものをアセンブリ言語、ニーモニックと呼ぶ。
パック・アンパック
ファイルの圧縮や解凍があるだろ、あれを実行ファイルにやることがパックだ。
なんだそんなことかよ…。とか思うなよ、パックのすごいところは圧縮されたままの状態で実行できるってことだ。
有名どころだと UPX や AS-Protect とかだな。
パックされている実行ファイルを解析する場合にはまずアンパックという作業が必要となる。いわば解凍だ。
なぜアンパックする必要があるかというと、パックされたファイルは内部的に自分自身の解凍ルーチンのようなものを保持している。
つまり実行プログラムのコード以外にも余計なものが入っており、そのままだと正しい情報が見れないわけだな。
ミジンコゼミではアンパックの方法には触れないが、パックされているネトゲのプログラムもあるから頭の片隅にでもいれておけ。
ちなみにプログラムがパックされているかどうかは PEiD で確認しろ。
アドレス
プログラム内で使われるデータはメモリ上に保存されている。
メモリ上といっても範囲が広いのでメモリ上のどこにデータがあるのか?を示すのがアドレスだ。
スタック
プログラムが使うデータを一時的に格納する場所がスタックだ。といったところで少々わかりづらいな…。
よし、紙切れ一枚一枚に「あ」「い」「う」「え」「お」と書いてみろ。つまり5つのデータ(紙切れ)が出来たわけだな。
次になんでもいいから箱を用意しろ。箱にはスタックと書いておけ。
そしてスタック(箱)の中にデータを書いた順番どおりにいれてみろ、データは一つ一つ重ねて入れるのがポイントだ。
これにより箱の一番したには「あ」があり、次に「い」、一番上には「お」がある。このようにデータを収める構造をスタックという。
スタックの原則としてデータを取り出すときに一番下にある「あ」をいきなり取り出すことは出来ない。
一番上にある「お」から順番に取り出さなきゃいかん。
≡命令文≡
アセンブリ言語で使う命令文だ。
Ollydbg などのデバッガにプログラムを食わせるとこの形式で表示される。最低でもこれくらいは意味がわかるようにしておけ。
それとな、初めて見るやつには多く感じるかもしれないが心配するな。こんなの覚えようとしなくても勝手に頭に入ってくるもんだ。
MOV:mov [dest] [src]
データの移動(厳密にはコピー)を行う
例1:数値2を eax にコピーする。
mov eax, 2 ; eax へ 2をコピー。
例2:変数 t1 に文字列 title が入っている場合。
eax に変数 t1 のアドレスをコピーする。
t1: db 'title',0 ; 変数t1 には文字列titleを定義
.
.
mov eax, t1
例3:変数 t1 に文字列 title が入っている場合。
eax に変数 t1 が示す値(title)をコピーする。
t1: db 'title',0 ; 変数t1 に文字列titleを定義
.
.
mov eax, [t1]
ADD:add レジスタ1, レジスタ2 or 数値
指定した値で加算する。演算結果はレジスタ1で指定したレジスタになる。
例1:eax と edx を足し、結果を eax に保存する。
mov eax, 4
mov ebx, 1
add eax, ebx
SUB:add レジスタ1, レジスタ2 or 数値
指定した値で減算する。演算結果はレジスタ1で指定したレジスタになる。
例1:eax から edx を減算し、結果を eax に保存する。
mov eax, 4
mov ebx, 1
sub eax, ebx
MUL:add レジスタ1, レジスタ2 or 数値
指定した値で乗算する。演算結果はレジスタ1で指定したレジスタになる。
例1:eax と edx で乗算し、結果を eax に保存する。
mov eax, 7
mov ebx, 2
mul ebx
DIV:add レジスタ1, レジスタ2 or 数値
指定した値で除算する。演算結果はレジスタ1で指定したレジスタになる。余りは edx レジスタに保存される。
例1:eax と edx で乗算し、結果を eax に保存する。余りは edx に保存される。
mov eax, 7
mov ebx, 2
mov edx, 0
div ebx
CMP:cmp 比較対照1, 比較対照2
比較対照1と比較対照2の値が等しいかどうかを判定する。等しい場合はZフラグが1に、等しくない場合は0(ゼロ)になる。
例1:eax と ebx の値を比較する。
mov eax, 5
mov ebx, 5
cmp eax, ebx ⇒ 等しいのでZフラグは1に変わる。
JMP:jmp [あて先アドレス]
指定したアドレスへ処理をジャンプさせる。ジャンプした先の処理が終わってもジャンプ元の処理には戻らない。
例1:プログラム内のアドレス 401000 の処理へジャンプする。
push 1
push 2
JMP 402000 ⇒ 次の処理 push 10 は飛ばされ、アドレス402000 の push 40 以降の処理を行う。
push 10
.
.
push 40
JE:JE [あて先アドレス]
Zフラグが1の場合、指定したあて先アドレスへJMPする。
例1:eax がゼロの場合、アドレス402000の処理へ飛ぶ。
mov eax, 0
cmp eax, 0
je 402000
JNE:JNE [あて先アドレス]
Zフラグがゼロではない場合、指定したアドレスへJMPする。
例1:eax が1の場合、アドレス402000の処理へ飛ぶ。
mov eax, 1
cmp eax, 0
jne 402000
CALL:call [処理]
指定した処理(APIや関数)を呼び出す。CALLはJMPと違って、処理終了後に呼び出し元の処理に戻ってくる。
例1:MessageBox API を呼び出す。
push 0
push "title"
push "text"
push 0
call MessageBox ⇒ 処理終了後は次の処理 push 10 を行う。
push 10
INC:inc レジスタ
指定したレジスタの値に1を加算する。
例1:eax の値を5から6へ。
mov eax, 5
inc eax
DEC:dec レジスタ
指定したレジスタの値から1を減算する。
例1:eax の値を5から4へ。
mov eax, 5
inc eax
PUSH:push レジスタ or 数値
指定した値をスタックへいれる。
例1:スタックへ 10 を格納。
push 10
POP:pop レジスタ
スタックから値を取り出す。
例1:スタックから eax へ 10 を取り出す。
pop eax
AND、OR、XOR:and、 or、 xor、 レジスタ or 数値, レジスタ or 数値
それぞれ論理積(and)、論理和(or)、排他的論理和(xor)をとる。
具体的には・・・ゴホンゴホン・・・
ミジンコゼミでもそのうち書き足しておくから今日のところは ここのページを見てこい!
それとレジスタ、フラグについても記載されてるからちゃんと見てこいよ!
とりあえずこんなもんだがもし追加しておいたほうがいいものを見つけたら
Mijinko Semi Top のコメント欄に書いておけ。
明日はウォーミングアップにもなりゃしないが 簡単な演習をするぞ。
|